using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;

using org.synthful.Profiles;

namespace org.synthful.Diagnostics
{
    /// <summary>
    /// Offered under Apache Public Licence 2.0
    /// synthful.org
    /// blessedgeek [@] synthful.org
    /// 
    /// Diagnostic logger.
    /// TBD: subclass Trace and TraceListeners.
    /// </summary>
    public class Flogger
    {
        static public FlogDescriptor DefaultLogDescriptor;
        static public FlogMode DefaultLogMode = new FlogMode();
        static public string DefaultDateFormat = "u";
        const string FlogRecSepr = " : ";

        static Flogger()
        {
            FlogSet logSet =
                new FlogSet(
                    AppFolders.AppDataFolder,
                    AppFolders.AppName,
                    AppFolders.AppName);

            DefaultLogDescriptor = new FlogDescriptor(logSet, DefaultLogMode, DefaultDateFormat);
        }

        static public void trace(byte traceLevel, params object[] textArray)
        {
            if (DefaultLogMode.Debug && traceLevel<= DefaultLogMode.Level)
            {
                Console.Write(DateTime.Now.TimeOfDay.ToString() + ':');
                if (textArray != null)
                {
                    for (int i = 0; i < textArray.Length; i++)
                    {
                        if (textArray[i] != null)
                            Console.Write(textArray[i].ToString());
                        Console.Write(';');
                    }
                    Console.Write(Environment.NewLine);
                }
            }
        }


        private static void write(Object caller, FlogDescriptor logDesc, bool append, params string[] data)
        {
            if (data.Length == 0)
                return;

            DateTime dt = DateTime.Now;
            string pid
                = logDesc.LogMode.ShowPID
                ? string.Concat(FlogRecSepr, "pid", Process.GetCurrentProcess().Id, FlogRecSepr)
                : string.Empty
                ;

            string callerTypeName = getCallerType(caller);

            string logRecord =
                string.Concat(dt.ToString(logDesc.DateFormat), FlogRecSepr, pid, callerTypeName);

            for (int i=0; i<data.Length; i++)
                logRecord =
                    string.Concat(logRecord, FlogRecSepr, data[i]);

            try
            {
                string logFile = logDesc.LogFileSet.ToString();
                Directory.CreateDirectory(logDesc.LogFileSet.Folder);
                StreamWriter logWriter =
                    new StreamWriter(logFile, append);
                logWriter.WriteLine(logRecord);
                logWriter.Flush();
                logWriter.Close();

                if (logDesc.LogToConsole)
                {
                    Console.WriteLine(logRecord);
                }
            }
            catch
            {
                return;
            }

        }

        static private string getCallerType(object caller)
        {
            if (caller != null)
                return string.Concat(caller.ToString(), FlogRecSepr);

            return string.Empty;
        }

    }

    public class FlogDescriptor
    {
        public FlogDescriptor(
            FlogSet flogSet, FlogMode flogMode, string dateFormat)
        {
            LogMode
                = (flogMode == null)
                ? new FlogMode()
                : flogMode
                ;

            string tmpLogToConsole = null;
            LogToConsole = tmpLogToConsole != null && tmpLogToConsole.Equals("true");

            DateFormat
                = (dateFormat == null)
                ? "MMM-dd-HH:mm:ss"
                : DateFormat = dateFormat
                ;

            LogFileSet = flogSet;
        }

        public FlogSet LogFileSet = null;
        public FlogMode LogMode = null;
        public string DateFormat = null;
        public bool LogToConsole = false;
        public Object LogKey;
    }


    public class FlogSet
    {
        public FlogSet(String rootFol, String subFol, String namePref)
        {
            RootFolder = rootFol;
            SubFolder = subFol;
            NamePrefix = namePref;
        }

        override public string ToString()
        {
            return
                string.Concat(
                    RootFolder,
                    SubFolder,
                    NamePrefix, '_',
                    DateTime.Now.ToString(FILENAME_DATE_FORMAT),
                    FILENAME_EXT
                );
        }

        public string Folder
        {
            get
            {
                return string.Concat(RootFolder, SubFolder);
            }
        }

        protected string namePrefix;
        public string NamePrefix
        {
            get
            {
                return namePrefix;
            }

            protected set
            {
                namePrefix = (value == null || value.Length == 0)
                ? Process.GetCurrentProcess().ProcessName
                : value
                ;
            }
        }

        protected string rootFolder;
        public string RootFolder
        {
            get
            {
                if (rootFolder.EndsWith("/") || rootFolder.EndsWith("\\"))
                    return rootFolder;

                return rootFolder + '/';
            }
            protected set
            {
                rootFolder
                    = (value == null || value.Length == 0)
                    ? AppFolders.AppProgramFolder
                    : value
                    ;
            }
        }

        protected string subFolder;
        public string SubFolder
        {
            get
            {
                if (subFolder.EndsWith("/") || subFolder.EndsWith("\\"))
                    return subFolder;

                return subFolder + '/';
            }
            protected set
            {
                subFolder
                    = (value == null || value.Length == 0)
                    ? "logs/" + (Process.GetCurrentProcess()).ProcessName + '/'
                    : value
                    ;
            }
        }

        public const string FILENAME_DATE_FORMAT = "yyyMMdd";
        public const string FILENAME_EXT = ".log";
    }

    public class FlogMode
    {
        public bool
            Info, Debug, ShowPID;
        public byte Level;
    }
}
